# coding:utf-8
import datetime
import logging.handlers

from flask import Flask, render_template, request, redirect, url_for, session, flash
from werkzeug.security import generate_password_hash

import config
from decorators import login_limit, permission_required_for_administrator, permission_required_for_responsibility
from exts import db
from forms import LoginForm, RegisterForm, ChangePwdForm
from log.log_processsing import read_line
from models import User, News, Permission

logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)

rf_handler = logging.handlers.TimedRotatingFileHandler('log/all.log', when='D',
                                                       interval=15,
                                                       backupCount=50,
                                                       atTime=datetime.time(0, 0, 0, 0))
rf_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))

f_handler = logging.FileHandler('log/error.log')
f_handler.setLevel(logging.ERROR)
f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))

logger.addHandler(rf_handler)
logger.addHandler(f_handler)

app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)


@app.route('/')
@app.route('/index', methods=['GET', 'POST'])
@app.route('/index/<int:page>', methods=['GET', 'POST'])
def index(page=1):
    context_for_per_page = News.query.filter_by(checked=True).order_by(News.create_time.desc()).paginate(page,
                                                                                                         config.NEWS_PER_PAGE,
                                                                                                         False)
    return render_template('index.html', context=context_for_per_page)


@app.route('/login/', methods=['GET', 'POST'])
def login():
    forms = LoginForm()
    if request.method == 'GET':
        return render_template('login.html', forms=forms)
    else:
        if forms.validate_on_submit():
            data = forms.data
            user = User.query.filter(User.uname == data['username']).first()
            if user and user.check_pwd(data['password']):
                session['user_id'] = user.id
                logger.info('login -- by user ' + str(user.uname))
                return redirect(url_for('index'))
            else:
                flash('用户名或密码错误', category='danger')
                logger.warning('login error -- error username or wrong password')
        else:
            flash('不能为空', category='danger')
            logger.warning('login error -- no username or password found')
        return render_template('login.html', forms=forms)


@app.route('/register/', methods=['GET', 'POST'])
def register():
    forms = RegisterForm()
    if request.method == 'GET':
        return render_template('register.html', forms=forms)
    else:
        if forms.validate_on_submit():
            data = forms.data
            account1 = User.query.filter_by(uname=data['uname']).count()
            account2 = User.query.filter_by(tel=data['tel']).count()
            if account1 == 1:
                flash("当前用户名已存在，请重试", category='danger')
                logger.warning('register error -- username already existed')
                return redirect(url_for('register'))
            elif account2 == 1:
                flash("当前手机号已被注册,请重试", category='danger')
                logger.warning('register error -- telephone has been used')
                return redirect(url_for('register'))
            else:
                user = User(tel=data['tel'],
                            uname=data['uname'],
                            pwd=data['pwd'],
                            )
                db.session.add(user)
                db.session.commit()
                # 注册成功则跳转到登录界面
                flash("注册成功", 'ok')
                logger.info('register -- by user ' + str(user.uname))
                return redirect(url_for('login'))
        return render_template('register.html', forms=forms)


@app.route('/allow_news', methods=['GET', 'POST'])
@app.route('/allow_news/<int:page>', methods=['GET', 'POST'])
@login_limit
@permission_required_for_responsibility(Permission.RELEASE_NEWS)
def allow_news(page=1):
    wait_for_check = News.query.filter_by(checked=False).paginate(page, config.NEWS_PER_PAGE, False)
    return render_template('allow_news.html', check_list=wait_for_check)


@app.route('/pass_news', methods=['GET', 'POST'])
@login_limit
@permission_required_for_responsibility(Permission.RELEASE_NEWS)
def pass_news():
    ops = request.args.get('pass')
    q = News.query.filter_by(id=ops).first()
    q.checked = True
    db.session.commit()
    return redirect(url_for('allow_news'))


@app.route('/fail_news', methods=['GET', 'POST'])
@login_limit
@permission_required_for_responsibility(Permission.RELEASE_NEWS)
def fail_news():
    ops = request.args.get('fail')
    q = News.query.filter_by(id=ops).first()
    db.session.delete(q)
    db.session.commit()
    return redirect(url_for('allow_news'))


@app.route('/rearrange/', methods=['GET', 'POST'])
@login_limit
@permission_required_for_responsibility(Permission.REARRANGE_NEWS)
def rearrange_news():
    return "For news rearrange!!"


@app.route('/right_manage/', methods=['GET', 'POST'])
@app.route('/right_manage/<int:page>', methods=['GET', 'POST'])
@login_limit
@permission_required_for_administrator
def right_manage(page=1):
    users = User.query.filter(User.role_id < 3).paginate(page, config.USER_PER_PAGE, False)
    return render_template('right_manage.html', users=users)


@app.route('/level_up/', methods=['GET', 'POST'])
@login_limit
@permission_required_for_administrator
def level_up():
    ops_name = request.args.get('upgrade')
    q = User.query.filter_by(uname=ops_name).first()
    q.role_id = q.role_id + 1
    db.session.commit()
    logger.info(str(q.uname) + ' level up to ' + str(q.role_id))
    return redirect(url_for('right_manage'))


@app.route('/level_down/', methods=['GET', 'POST'])
@login_limit
@permission_required_for_administrator
def level_down():
    ops_name = request.args.get('downgrade')
    q = User.query.filter_by(uname=ops_name).first()
    q.role_id = q.role_id - 1
    db.session.commit()
    logger.info(str(q.uname) + ' level down to ' + str(q.role_id))
    return redirect(url_for('right_manage'))


@app.route('/log_manage/')
@login_limit
@permission_required_for_administrator
def log_manage():
    logs = read_line('log/all.log')
    return render_template('log_manage.html', logs=logs)


@app.route('/file_manage/')
@login_limit
@permission_required_for_administrator
def file_manage():
    return "For file management!"


@app.route('/logout/')
def logout():
    logger.info('logout -- by user_id ' + str(session['user_id']))
    session.pop('user_id')
    return redirect(url_for('login'))


@app.route('/change_pwd/', methods=['GET', 'POST'])
@login_limit
def change_pwd():
    forms = ChangePwdForm()
    if request.method == 'GET':
        return render_template('change_pwd.html', forms=forms)
    else:
        if forms.validate_on_submit():
            data = forms.data
            user_id = session.get('user_id')
            user = User.query.filter_by(id=user_id).first()
            if not user.check_pwd(data['old_pwd']):
                flash('旧密码输入错误', category='danger')
                logger.warning('password change error -- old password is wrong')
                return redirect(url_for('change_pwd'))
            elif data['conf_pwd'] != data['new_pwd']:
                flash('两次新密码不一致', category='danger')
                logger.warning('password change error -- two new passwords is not same')
                return redirect(url_for('change_pwd'))
            else:
                user.pwd = generate_password_hash(data['new_pwd'])
                db.session.add(user)
                db.session.commit()
                flash('修改成功', 'ok')
                logger.info('password change -- by user ' + str(user.uname))
                logout()
                # 注册成功则跳转到登录界面
                return redirect(url_for('login'))
        return render_template('change_pwd.html', forms=forms)


@app.route('/news/', methods=['GET', 'POST'])
@login_limit  # 发布新闻需要登陆
def release_news():
    if request.method == 'GET':
        return render_template('release_news.html')
    else:
        title = request.form.get('title')
        content = request.form.get('content')
        news = News(title=title, content=content, checked=False)
        user_id = session.get('user_id')
        user = User.query.filter(User.id == user_id).first()
        news.author = user
        db.session.add(news)
        db.session.commit()
        logger.info('news released -- by user ' + str(user.uname))
        return redirect(url_for('index'))


@app.route('/news_detail/<news_id>/')
def news_detail(news_id):
    one_news = News.query.filter(News.id == news_id).first()
    return render_template('news_detail.html', news=one_news)


@app.context_processor
def my_context_processor():
    user_id = session.get('user_id')
    if user_id:
        user = User.query.filter(User.id == user_id).first()
        if user:
            return {'user': user}
    else:
        return {}


def inject_permissions():
    return dict(Permission=Permission)


if __name__ == '__main__':
    app.run()
